<?php
defined('BASEPATH') OR exit('No direct script access allowed');
/**
 * 获取通行证类
 */
class PassPort{
	private $user_model,$cooper_key,$redis;
	private $otp_expire,$expire;
	protected $ci;
	private $authcode_key,$auth_key,$skey_len;
	private $cookie_domain,$secure;
	private $cooper,$platform;
	
	function __construct(){
		$this->ci = & get_instance();
		$this->ci->load->model('user_model');
		$this->user_model = $this->ci->user_model;
		$this->cooper_key = $this->ci->config->item('cooper_key');

		//链接redis
		$this->ci->load->driver('cache');
		$this->ci->cache->redis->is_supported();
		$this->redis = $this->ci->cache->redis;

		$this->expire = 43200;//登录默认过期时间
		$this->otp_expire = 300;//5分钟过期
		$this->skey_len	= '32';
		$this->secure = $this->ci->config->item('cookie_secure');
		$this->auth_key	 = md5('~%4^23s5D#@3d4722#FGA54s6@45dF#f8s^&8D*&^');
		$this->authcode_key	= md5('@$G35D#@3dFHb@dff^&*d34dF#f5D32&8D*@#4');
		$this->cookie_domain = $this->ci->config->item('cookie_domain');
		$this->cooper = 1;
		$this->platform = 1;
	}

	public function setCooper($cooper){
		$this->cooper = $cooper;
	}

	public function setPlatform($platform){
		$this->platform = $platform;
	}

	/*
    * 获取OTP
    * 生成OTP、创建通行證帐号
    */
	public function getOtp($data){
		foreach ($data as $key => $val) {
			$$key = $val;
		}
		unset($data);
		$register = isset($register)?$register:0;
		//返回数据格式
		$format = "platform=%s&cooper=%s&token=%s&result=%s&otp=%s&signmsg=%s&uid=%s";
		//验证参数是否合法
        if(empty($token)) {
            return sprintf($format,$this->platform,$this->cooper,$token,'1002','','','');
        }
		if(!regex($phone,'mobile')){
			return sprintf($format,$this->platform,$this->cooper,$token,'1003','','','');
		}
        $verify_msg = strtoupper(md5($this->platform . $this->cooper . $this->cooper_key . $token));
        if($signmsg != $verify_msg) {
           return sprintf($format,$this->platform,$this->cooper,$token,'1004','',$verify_msg,'');
        }
        
        $whereArr = array(
        	'platform' => $this->platform,
        	'token' => $token,
        );
        $datetime = date('Y-m-d H:i:s',$time);
        $userData = $this->user_model->getUserInfoByMulti($whereArr);
        $btc = 0;
        if(empty($userData)) {//如果为空，则创建用户
        	if($register == 0){
				//帐号不存在
				return sprintf($format,$this->platform,$this->cooper,$token,'1006','',$signmsg,'');
			}
			$i = 1;
			do{
				//其他平台进来的用户，默认没有密码，必须重新设置密码
				if(empty($password)){
					$password	=	'11111111111111111111111111111111';
				}else{
					$password	= 	md5(md5($password.$time).$time);
				}
				$userData = array(
					'platform' => $this->platform,
					'cooper' => $this->cooper,
					'area' => $area,
					'phone' => $phone,
					'password' => $password,
					'token' =>	$token,
					'account' => strtolower(md5(md5($this->platform."@".$this->cooper."@".$token))),
					'btc' => $btc,
					'comefrom' => $comefrom,
					'lang' => $lang,
					'reg_flag' => $reg_flag,
					'create_ip' => $user_ip,
					'create_time' => $datetime,
					'email_flag' =>	0
				);
				if(isset($openid)) $userData['openid'] = $openid;
				$uid = $this->user_model->addUser($userData);
				$userData['uid'] = $uid;
			}while(false == $uid  && $i++ < 5 && empty($msg));
			if(false == $uid){
				return sprintf($format,$this->platform,$this->cooper,$token,'1005','',$signmsg,'');
			}
        }else{
			if($register == 1){
				//帐号已经存在
				return sprintf($format,$this->platform,$this->cooper,$token,'1006','',$signmsg,'');
			}
		}
		//生成otp
		$i = 1;
		do {
			$otp = $userData['uid'] . rand(1000000,9999999) . date('ymdHis');
			$data = array(
				"otp" => $otp,
				"platform" => $this->platform,
				"cooper" => $this->cooper,
				"token" => $token,
				"uid" => $userData['uid'],
				"time" => time(),
				"ip" => get_ip(),
				"user_ip" => $user_ip,
				"status" => 1,
			);
			$rs = $this->saveAccess($data);
		}while(!$rs && $i++ < 5 && empty($msg));
		if(!$rs){
			//通行证无法存储
			return sprintf($format,$this->platform,$this->cooper,$token,'1007','',$signmsg,'');
		}
		$signmsg = strtoupper(md5($this->platform . $this->cooper . $token . '1001' . $otp . $this->cooper_key));
		return sprintf($format,$this->platform,$this->cooper,$token,'1001',$otp,$signmsg,$userData['uid']);
	}

	/**
	 * 保存通行证
	 * @return [type] [description]
	 */
	private function saveAccess($data=array()){
		if(empty($data['otp'])) return false;
		$otp = $data['otp'];
		$otpKey = "OTP|".$this->platform."|".$this->cooper."|$otp";
		$rs	= $this->redis->getClient()->hmset($otpKey,$data);
		$this->redis->getClient()->expire($otpKey,$this->otp_expire);
		return $rs;
	}

	/**
	 * 获取通行证
	 * @return [type] [description]
	 */
	public function getAccess($otp = NULL){
		if($otp == NULL) return false;
		$otpKey = "OTP|".$this->platform."|".$this->cooper."|$otp";
		$rs	= $this->redis->getClient()->hgetall($otpKey);
		return $rs;
	}

	/**
	 * 删除通行证
	 * @return [type] [description]
	 */
	public function delAccess($otp = NULL){
		if($otp == NULL) return false;
		$otpKey = "OTP|".$this->platform."|".$this->cooper."|$otp";
		$rs	= $this->redis->getClient()->delete($otpKey);
		return $rs;
	}

	/**
	 * 检查某一帐号是否已经登录[主要用于禁止重复登录]
	 * @param int	$uid	通行证编号
	 * @return bool
	 */
	public function checkOnline($uid) {
		$this->ci->load->model('online_model');
		$onlineData = $this->ci->online_model->getOnline(array('platform'=>$this->platform,'cooper'=>$this->cooper,'uid'=>$uid));
		return $onlineData;
	}

	/**
	 * 把一个帐号踢下线
	 * @param int	$skey	通行证编号
	 * @return bool
	 */
	public function kickOffline($skey) {
		$this->ci->load->model('online_model');
		$this->ci->online_model->delOnline(array('platform'=>$this->platform,'cooper'=>$this->cooper,'skey'=>$skey));
		$this->redis->getClient()->delete("ONLINE|".$this->platform."|$skey");
		return true;
	}

	/**
	 * 删除超过时间没更新动作的用户
	 */
	public function deleteOverTime() {
		$this->ci->load->model('online_model');
		$onlineData = $this->ci->online_model->getOnline(array('expire_time <'=>time()));
		if(!empty($onlineData)) foreach($onlineData as $items){
			$this->kickOffline($items['skey']);
		}
		return true;
	}

	/**
	 * 设置在线表过期时间
	 * @param unknown $seconds
	 */
	public function setExpire($seconds){
		$this->expire = $seconds;
	}

	/**
	 * 检查通行证状态
	 * @param string	$skey			在线状态唯一标识[相当于Cache id]
	 * @param string	$authcode		验证码[用于检验通行证在线资料的合法性]
	 * @param bool		$return_info	是否需要返回帐号详细资料[若为true则返回的是数组资料]
	 * @return bool
	 */
	public function checkCookieAuthCode($skey = '', $authcode = '', $return_info = false, $ajax = false) {
		if(empty($_COOKIE['skey'])) $_COOKIE['skey'] = '';
		if(empty($_COOKIE['authcode'])) $_COOKIE['authcode']	=	'';
		$skey =	(!empty($skey))?$skey:$_COOKIE['skey'];
		$authcode= (!empty($authcode))?$authcode:$_COOKIE['authcode'];
		if (empty($skey) || empty($authcode)){//当验证码不存在时
			return false;
		}

		//检查缓存存储的IP信息，进行对比
		// if(!$this->checkLoginIP()){
		// 	return false;
		// }
		
		//查看有没过期缓存
		$onlineKey = "ONLINE|".$this->platform."|$skey";
		$i = 0;
		do{
			$cacheOnlie = $this->redis->getClient()->hgetall($onlineKey);
		}while(empty($cacheOnlie) && $i++ < 2);
		if (empty($cacheOnlie)){
			$this->kickOffline($skey);
			return false;
		}
		$uid = $cacheOnlie['uid'];
		$password = $cacheOnlie['rand_password'];
		if ($uid < '1' || $this->checkAuthcode($skey, $uid, $password, $authcode) != true) {
			$this->redis->getClient()->delete($onlineKey);
			$this->redis->getClient()->delete("USERINFO|$uid");
			return false;
		}else{
			$userInfo = $this->user_model->getUserInfo(array('uid'=>$uid),true);
			$cache_expire	=	isset($userInfo['cache_expire'])?$userInfo['cache_expire']:43200;
			//设置用户信息最后更新时间
			$this->setExpire($cache_expire);//设置在线误操作过期时间
			if(!$ajax){//定时刷新的不更新在线表
				if(($cacheOnlie['lastest_update']+60) < time()){//为防止一直刷新 一分钟后才会刷新
					$this->updateOnlineInfo($uid, $skey, $password);
				}
			}
			if($return_info){
				return $userInfo;
			}
			return true;
		}
	}

	public function flushUserCache($uid){
		$this->redis->getClient()->delete("USERINFO|$uid");
	}

	/**
	 * 处理帐号退出的操作
	 */
	public function doLogout() {
		$skey = (!empty($skey))?$skey:$_COOKIE['skey'];
		if(!empty($skey)){
			$this->kickOffline($skey);
		}
		$this->clearCookieAuthCode();
		return true;
	}

	/**
	 * 生成随机密码[主要用于cookie中的验证字符串生成及有效性验证]
	 */
	public function makeRandPassword(){
		$s1 = rand(15,20);
		$t_arr = array();
		$t_str = '';
		$i = 0;
		while($i < $s1){
			$s = rand(33,127);
			$t_arr[] = chr($s);
			$i++;
		}
		if (!empty($t_arr))
			$t_str =implode('',$t_arr);
		return $t_str;
	}

	/**
	 * 生成一个随机的唯一标识
	 * @return string	$t_str
	 */
	private function makeSkey() {
		$string	= '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
		$s_len = strlen($string)-1;
		$t_str = '';
		$times = 0;
		$r = false;
		while($r == false && $times < '32'){
			$t_arr = array();
			for($i=0; $i<$this->skey_len; $i++){
				$t_arr[] = substr($string, rand(0,$s_len), 1);
			}
			$t_str = implode('',$t_arr);
			$onlineKey = "ONLINE|".$this->platform."|$t_str";
			$flag =	$this->redis->getClient()->hgetall($onlineKey);
			if($flag){ 
				$times++;
				continue;
			}
			$this->ci->load->model('online_model');
			$onlineData = $this->ci->online_model->getOnline(array('platform'=>$this->platform,'cooper'=>$this->cooper,'skey'=>$t_str));
			if (empty($onlineData)){
				$r = true;
			}
		}
		return $t_str;
	}

	/**
	 * 保存在线资料
	 * @param int	$uid			通行证编号
	 * @param string	$password	帐号密码
	 * @param string	$ip			所在IP
	 * @param string	$skey		在线状态唯一标识
	 */
	public function saveOnlineInfo($uid = '0', $password = '', $ip = '', $skey = '') { 
		$skey =	($skey == '')?$this->makeSkey():$skey;
		$password =	($password == '')?md5($this->makeRandPassword()):$password;
		if('' == $skey) return false;
		if(empty($uid)){
			return false;
		}
		$ipstr = ($ip == '') ? get_ip() : $ip;
		$iparr = explode('.', $ipstr);
		$ip1 = intval($iparr[0]);
		$ip2 = intval($iparr[1]);
		$ip3 = intval($iparr[2]);
		$ip4 = intval($iparr[3]);
		$time = time();
		$online_array = array(
			'skey' => $skey,
			'platform' => $this->platform,
			'cooper' => $this->cooper,
			'uid' => $uid,
			'rand_password' => $password,
			'ip1' => $ip1,
			'ip2' => $ip2,
			'ip3' => $ip3,
			'ip4' => $ip4,
			'expire_time' => bcadd($time,$this->expire),
			'lastest_login' => $time,
			'lastest_update' => $time,
			'system' => getSystem(),
			'browser' => getBrowser(),
		);
		$this->ci->load->model('online_model');
		$rs = $this->ci->online_model->addOnline($online_array);
	    if($rs) {
	    	$onlineKey = "ONLINE|".$this->platform."|$skey";
			$this->redis->getClient()->hMset($onlineKey,$online_array);
			$this->redis->getClient()->expire($onlineKey,$this->expire);
	        $this->saveCookieAuthcode($skey, $uid, $password);
			return true;
	    }else {
			return false;
		}
	}

	/**
	 * 更新在线用户的资料
	 * @param int		$uid	通行证编号
	 * @param string	$skey	在线状态唯一标识[保存于cookie]
	 * @param string	$ip		客户端IP
	 * @param bool		$islogin	是否帐号登录动作
	 * @param string	$password	帐号密码[md5之后的]
	 * @return bool
	 */
	public function updateOnlineInfo($uid, $skey, $password='', $ip = '') {
		if(empty($uid)) return false;
		$ipstr = ($ip == '')?get_ip():$ip;
	    $iparr = explode('.', $ipstr);
	    $ip1 = intval($iparr[0]);
	    $ip2 = intval($iparr[1]);
	    $ip3 = intval($iparr[2]);
	    $ip4 = intval($iparr[3]);
	    $time = time();
	    $online = array(
			'ip1' => $ip1,
			'ip2' => $ip2,
			'ip3' => $ip3,
			'ip4' => $ip4,
			'expire_time' => bcadd($time,$this->expire),
			'lastest_update'=> $time,
		);
		$where = "skey = '$skey'";
		$this->ci->load->model('online_model');
		$rs = $this->ci->online_model->updateOnline($online,$where);
		if($rs){
			$onlineKey = "ONLINE|".$this->platform."|$skey";
			$this->redis->getClient()->hMset($onlineKey,$online);
			$this->redis->getClient()->expire($onlineKey,$this->expire);
			//保存登录用户的当前IP每次操作前都要检查IP是否有效，无效直接die掉；
			// if($ipstr != ''){
			// 	$this->setLoginIP($ipstr);
			// }
		}
		return $rs;
	}

	/**
	 * 保存cookie资料
	 * @param string	$skey		在线状态唯一标识
	 * @param int		$uid		通行证编号[未登录则为0]
	 * @param string	$password	通行证密码[未登录则为空]	->	随机密码
	 */
	public function saveCookieAuthcode($skey, $uid = '0', $password = '') {
		$auth_code = $this->makeAuthCode($skey, $uid, $password);
		$_COOKIE['skey'] = $skey;
		$_COOKIE['authcode'] = $auth_code;
		$this->setCookieAuthcode('authcode', $auth_code, '0', $this->cookie_domain);
		$this->setCookieAuthcode('skey', $skey, '0', $this->cookie_domain);
	}

	/**
	 * 清空玩家客户端浏览器的cookie信息[用于帐号退出]
	 */
	public function clearCookieAuthCode(){
		$this->setCookieAuthcode('authcode', '1', 1, $this->cookie_domain);
		$this->setCookieAuthcode('skey', '1', 1, $this->cookie_domain);
	}

	public function setCookie($name,$value){
		$this->setCookieAuthcode($name, $value, '0', $this->cookie_domain);
	}

	/**
	 * 检查cookie中的验证码是否有效
	 * @param string	$skey		在线状态唯一标识
	 * @param int		$uid		通行证编号
	 * @param string	$password	通行证密码[经md5]
	 * 2param string	$authcode	要对比的字符串[跟$skey一样保存于cookie中]
	 * @return bool
	 */
	private function checkAuthcode($skey, $uid, $password, $authcode){
		$authcode	=	$this->disposeCode($authcode, 'DECODE');
		if (md5($this->authcode_key.$skey.$uid.$password) != $authcode) return false;
		else return true;
	}

	/**
	 * 设置cookie内容
	 * @param string	$name	名称
	 * @param string	$value	值
	 * @param int		$expire	有效期
	 * @param string	$domain	作用域
	 */
	private function setCookieAuthcode($name = '', $value = '', $expire = 0, $domain = ''){
		$name	=	$name == ''	?	'authcode'	:	$name;
		setcookie($name, $value, $expire, '/', $domain, $this->secure);
	}
	
	/**
	 * 清空cookie
	 * @param string	$name	名称
	 * @param string	$domain	作用域
	 */
	public function resetCookieAuthcode($name = '', $domain = ''){
		setcookie($name, '', '0', '/', $domain, $this->secure);
	}

	/**
	 * 生成通行证有效验证码
	 * @param string	$skey		在线状态唯一标识
	 * @param int		$uid		通行证编号[未登录则为0]
	 * @param string	$password	通行证密码[未登录则为空]	->	已换为随机密码
	 * @return string
	 */
	private function makeAuthCode($skey, $uid, $password){
		$code = md5($this->authcode_key.$skey.$uid.$password);
		$code = $this->disposeCode($code, 'ENCODE');
		return $code;
	}

	/**
	 * 加密/解密函数。源于Discuz
	 * @param string	$string		要加密/解密的字符串
	 * @param string	$operation	"DECODE" or "ENCODE"
	 * @param string	$key		密钥
	 * @return string	
	 */
	public function disposeCode($string, $operation, $key = '') {
		$key = md5($key ? $key : $this->auth_key);
		$key_length = strlen($key);
		$string	 = ($operation == 'DECODE') ? base64_decode($string) : substr(md5($string.$key), 0, 8).$string;
		$string_length = strlen($string);
		$rndkey = array();
		$box = array();
		$result = '';
		for($i = 0; $i <= 255; $i++) {
			$rndkey[$i] = ord($key[$i % $key_length]);
			$box[$i] = $i;
		}
		for($j = $i = 0; $i < 256; $i++) {
			$j = ($j + $box[$i] + $rndkey[$i]) % 256;
			$tmp = $box[$i];
			$box[$i] = $box[$j];
			$box[$j] = $tmp;
		}
		for($a = $j = $i = 0; $i < $string_length; $i++) {
			$a = ($a + 1) % 256;
			$j = ($j + $box[$a]) % 256;
			$tmp = $box[$a];
			$box[$a] = $box[$j];
			$box[$j] = $tmp;
			$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
		}
		if($operation == 'DECODE') {
			if(substr($result, 0, 8) == substr(md5(substr($result, 8).$key), 0, 8)) {
				return substr($result, 8);
			} else {
				return '';
			}
		} else {
			return str_replace('=', '', base64_encode($result));
		}
	}

}